package com.pentajock.docdb;

import com.pentajock.docdb.colors.Colors;
import com.pentajock.docdb.database.DBController;
import com.pentajock.docdb.dialogs.DepartmentPropertiesDialog;
import com.pentajock.docdb.dialogs.Dialogs;
import com.pentajock.docdb.dialogs.DocumentPropertiesDialog;
import com.pentajock.docdb.dialogs.ExtensionDialog;
import com.pentajock.docdb.dialogs.UserDialog;
import com.pentajock.docdb.images.DBImages;
import com.pentajock.docdb.types.User;
import com.pentajock.docdb.gui.TableRenderer;
import com.pentajock.docdb.gui.VisibleIndexList;
import com.pentajock.docdb.gui.DocumentResultListModel;
import com.pentajock.docdb.gui.ListRenderer;
import com.pentajock.docdb.gui.StatusBar;
import com.pentajock.docdb.lang.Lang;
import com.pentajock.docdb.listeners.FileDrop;
import com.pentajock.docdb.threads.DocumentThreadWorker;
import com.pentajock.docdb.types.Document;
import com.pentajock.docdb.types.WeightedDocument;
import com.pentajock.docdb.types.WeightedUser;
import com.pentajock.docdb.utils.QuickIni;
import com.pentajock.docdb.utils.Utils;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.awt.event.*;
import java.sql.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.colorchooser.*;
import javax.swing.UIManager.*;
import java.util.ArrayList;
import javax.swing.table.*;
import java.text.*;
import javax.swing.border.*;

public class AdminWindow extends JFrame {
	static private final String DELETE_INPUT_KEY = "DELETE_KEY";
	private int DUE_MONTHS_AHEAD = 1;
	//private java.util.List<Document> allDocuments;
	private User userAccount;
	/*
	 * Primary UI components
	 */
	private JScrollPane resultScroll;
	private JScrollPane navigatorScroll;
	private JSplitPane splitPane;
	private JPanel resultsPanel;
	private JPanel buttonPanel;
	private JTree navigatorTree;
	
	private JTable resultTable;
	private JButton[] panelButtons;
	
	private VisibleIndexList resultList;
	private StatusBar statusBar;
	private DocumentThreadWorker threadWorker;
	
	/*
	 * Dialogs
	 */
	JFileChooser folderChooser;
	 
	/*
	 * Menu Items
	 */
	private JPopupMenu listPopupMenu;
	private JMenuItem[] menuItems;
	/*
	 * Renderers, models, layouts
	 */
	private DocumentResultListModel resultListModel;
	private DocumentResultListModel allDocumentsListModel;
	private DefaultTableModel resultTableModel;
	private TableRenderer tableRenderer;
	private ListRenderer listRenderer;
	private GridLayout buttonGrid;
	/*
	 * Action references.
	 */
	private Action exitAction;
	private Action addUserAction;
	private Action editUserAction;
	private Action deleteUserAction;
	private Action approveAction;
	private Action assignAction;
	private Action disabledAction;
	private Action deleteDocumentAction;
	private Action deleteFileAction;
	private Action addExtensionAction;
	private Action editExtensionAction;
	private Action deleteExtensionAction;
	private Action applyLookAndFeelAction;
	private Action addDepartmentAction;
	private Action editDepartmentAction;
	private Action deleteDepartmentAction;
	private Action editColorAction;
	private Action unAssignAction;
	private Action documentPropertiesAction;
	private Action editCategoryAction;
	private Action addCategoryAction;
	private Action deleteCategoryAction;
	private Action deleteAction;
	private Action repopulateDatabaseAction;
	
	//
	public AdminWindow(User u) {
		super();
		setTitle(Lang.ADMIN_DIALOG.getText("TITLE", "Admin Window"));
		userAccount = u;
		ViewMode.listMode = ViewMode.NULL_MODE;
		//allDocuments = null;
		createActions();
		initializeUIComponents();
		layoutFrame();
		addListeners();
		setIconImage(DBImages.ADMIN_WINDOW.getImage());
		setPreferredSize(new Dimension(625, 500));
		setMinimumSize(new Dimension(625, 500));
		pack();
		setLocationRelativeTo(null);
		DUE_MONTHS_AHEAD = Math.max(Main.sysIni.getIntegerProperty("Admin View", "due_months_ahead"), 1);
		
		/* 
		 * Default View 
		 */
		listDueDocs();
	}
	
	private enum PathComponents {
		/*
		 * + = New Branch
		 * o = Current Brance
		 * - = Parent Branch
		 */
		ADMIN			("+" + Lang.ADMIN_DIALOG.getText("ADMIN", "Admin")),
		DOCUMENTS		("+" + Lang.ADMIN_DIALOG.getText("DOCUMENTS", "Documents")),
		DUE_DOCUMENTS 		("o" + Lang.ADMIN_DIALOG.getText("DOCUMENTS_DUE", "Due Documents")),
		ALL_DOCUMENTS 		("o" + Lang.ADMIN_DIALOG.getText("DOCUMENTS_ALL", "All Documents")),
		ASSIGNED_DOCUMENTS	("o" + Lang.ADMIN_DIALOG.getText("DOCUMENTS_ASSIGNED", "Assigned Documents")),
		AWAITING_DOCUMENTS 	("o" + Lang.ADMIN_DIALOG.getText("DOCUMENTS_AWAITING","Awaiting Approval")),
		USERS 			("-" + Lang.ADMIN_DIALOG.getText("USER_ACCOUNTS", "Users")),
		DEPARTMENTS 		("o" + Lang.ADMIN_DIALOG.getText("USER_DEPARTMENTS", "Departments")),
		EXTENSIONS 		("o" + Lang.ADMIN_DIALOG.getText("EXTENSIONS", "Extensions")),
		CATEGORIES 		("o" + Lang.ADMIN_DIALOG.getText("CATEGORIES", "Categories")),
		FILE_SERVERS 		("o" + Lang.ADMIN_DIALOG.getText("FILE_SERVERS", "File Servers")),
		ICONS 			("o" + Lang.ADMIN_DIALOG.getText("ICONS", "Icons")),
		LOOK_AND_FEEL 		("o" + Lang.ADMIN_DIALOG.getText("LOOK_AND_FEEL", "Look and Feel")),
		COLORS 			("o" + Lang.ADMIN_DIALOG.getText("COLORS", "Colors")),
		DATABASE_FUNCTIONS 	("o" + Lang.ADMIN_DIALOG.getText("DATABASE_FUNCTIONS", "Database Functions"));
		
		String name;
		PathComponents(String name) {
			this.name = name;
		}
		
		public PathComponents[] getComponents() {
			return values();
		}
		
		private boolean newBranch() {
			return name.startsWith("+");
		}
		
		private boolean prevBranch() {
			return name.startsWith("-");
		}
		
		private boolean sameBranch() {
			return name.startsWith("o");
		}
		
		public String toString() {
			return name.substring(1, name.length());
		}
		
		public static DefaultTreeCellRenderer noIconRenderer() {
			DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer();
			defaultRenderer.setOpenIcon(null);
			defaultRenderer.setClosedIcon(null);
			defaultRenderer.setLeafIcon(null);
			return defaultRenderer;
		}
		
		public static JTree buildTree() {
			JTree allNodesTree = new JTree(getTreeNodes());
			allNodesTree.setCellRenderer(noIconRenderer());
			allNodesTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
			return allNodesTree;
		}
		
		private static TreeNode getTreeNodes() {
			DefaultMutableTreeNode rootNode = null;
			DefaultMutableTreeNode fatherNode = null;
			DefaultMutableTreeNode childNode;
			String nodeName;
			for (PathComponents p : values()) {
				if (rootNode == null) {
					rootNode = new DefaultMutableTreeNode(ADMIN);
					fatherNode = rootNode;
					continue;
				}
				
				nodeName = p.toString();
				
				childNode = new DefaultMutableTreeNode(p);
				if (p.newBranch()) {
					fatherNode.add(childNode);
					fatherNode = childNode;
				}
				else if (p.prevBranch()) {
					fatherNode = (DefaultMutableTreeNode)fatherNode.getParent();
					fatherNode.add(childNode);
				}
				else if (p.sameBranch()) {
					fatherNode.add(childNode);
				}
			}
			return rootNode;
		}
	}
	
	private void layoutFrame() {
		for (JButton j : panelButtons) {
			j.setBorder(BorderFactory.createEtchedBorder());
		}
		
		GridBagLayout gridBag = new GridBagLayout();
		GridBagConstraints c = new GridBagConstraints();
		buttonGrid = new GridLayout(1, 1, 8, 8);
		buttonPanel.setLayout(buttonGrid);
		resultsPanel = new JPanel(gridBag);
		
		c.gridx = 0;
		c.gridy = 0;
		c.weightx = 1.0;
		c.weighty = 1.0;
		c.fill = GridBagConstraints.BOTH;
		gridBag.setConstraints(resultScroll, c);
		resultsPanel.add(resultScroll);
		
		c.gridx = 0;
		c.gridy = 1;
		c.weightx = 0.0;
		c.weighty = 0.0;
		c.fill = GridBagConstraints.NONE;
		gridBag.setConstraints(buttonPanel, c);
		resultsPanel.add(buttonPanel);
		
		navigatorScroll.setMinimumSize(new Dimension(150, this.getHeight()));
		
		splitPane.setLeftComponent(navigatorScroll);
		splitPane.setRightComponent(resultsPanel);
		
		getContentPane().add(splitPane, BorderLayout.CENTER);
		getContentPane().add(statusBar, BorderLayout.SOUTH);
	}
	
	private void initializeUIComponents() {
		Utils.applyFileChooserTweak();
		folderChooser = new JFileChooser();
		listRenderer = new ListRenderer(userAccount);
		tableRenderer = new TableRenderer(userAccount);
		statusBar = new StatusBar(this);
		navigatorTree = PathComponents.buildTree();
		navigatorTree.expandRow(1);
		navigatorTree.setSelectionRow(2);
		panelButtons = new JButton[5];
		menuItems = new JMenuItem[5];
		for (int i = 0; i < panelButtons.length; i++) {
			panelButtons[i] = new JButton("Disabled");
			panelButtons[i].setEnabled(false);
			menuItems[i] = new JMenuItem();
		}
		
		navigatorScroll = new JScrollPane(navigatorTree);
		resultTableModel = new DefaultTableModel(0,0) {
			public boolean isCellEditable(int r, int c) {
				return false;
			}
		};
		
		JMenuBar menuBar = new JMenuBar();
		JMenu fileMenu = new JMenu("File");
		fileMenu.setMnemonic(KeyEvent.VK_F);
		fileMenu.add(new JMenuItem(exitAction));
		menuBar.add(fileMenu);
		setJMenuBar(menuBar);
		
		resultListModel = new DocumentResultListModel();
		allDocumentsListModel = new DocumentResultListModel();
		resultList = new VisibleIndexList(resultListModel);
		resultTable = new JTable(resultTableModel);
		resultScroll = new JScrollPane(resultList);
		buttonPanel = new JPanel();
		splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
		listPopupMenu = new JPopupMenu();
		resultList.setCellRenderer(listRenderer);
		Main.setCursor(this, Cursor.DEFAULT_CURSOR);
		threadWorker = new DocumentThreadWorker(allDocumentsListModel, this, statusBar);
	}
	
	private void createActions() {
		exitAction = new AbstractAction("Exit", DBImages.EXIT_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				closeWindow();
			}
		};
		exitAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_X);
		
		addUserAction = new AbstractAction("Add User", DBImages.USER_ADD_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				openUserDialog(true);
			}
		};
		addUserAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
		
		editUserAction = new AbstractAction("Edit User", DBImages.USER_EDIT_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				openUserDialog(false);
			}
		};
		editUserAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E);
		
		deleteUserAction = new AbstractAction("Delete User", DBImages.USER_REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				deleteUser();
			}
		};
		deleteUserAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
		
		disabledAction = new AbstractAction("Disabled"){
			public void actionPerformed(ActionEvent e) {
				// Do nothing
			}
		};
		
		deleteAction = new AbstractAction("Delete", DBImages.REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				Object o = resultList.getSelectedValue();
				switch (ViewMode.listMode) {
					case USER_MODE:	deleteUser(); break;
					case DEPARTMENT_MODE: deleteDepartment(); break;
					case AWAITING_MODE: ; //Move down
					case ASSIGNED_MODE: ; //Move down
					case DOCUMENT_MODE: deleteDocument(o); break;
					case EXTENSION_MODE: deleteExtension(); break;
					case CATEGORY_MODE: deleteCategory(); break;
					default: break;
				}
			}
		};
		
		repopulateDatabaseAction = new AbstractAction("Re-Populate", DBImages.GENERIC_ICON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				repopulateDatabase();
			}
		};
		
		deleteDepartmentAction = new AbstractAction("Delete Department", DBImages.GROUP_REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				Dialogs.confirmDelete(resultList.getSelectedValue());
				//
			}
		};
		deleteDepartmentAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D); 
		
		addDepartmentAction = new AbstractAction("Add Department", DBImages.GROUP_ADD_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				openDialogWindow(null);
				//
			}
		};
		addDepartmentAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
		
		editDepartmentAction = new AbstractAction("Edit Department", DBImages.GROUP_EDIT_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				openDialogWindow(resultList.getSelectedValue());
				//
			}
		};
		editDepartmentAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E);
		
		deleteDocumentAction = new AbstractAction("Delete", DBImages.REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				deleteDocument(resultList.getSelectedValue());
			}
		};
		deleteDocumentAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
		
		deleteFileAction = new AbstractAction("Delete", DBImages.REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				Object o = resultList.getSelectedValue();
				if (o instanceof Document) {
					if (Dialogs.confirmDelete(o) && ((Document)o).toAwaitingFile(userAccount).delete()) {
						Dialogs.showSuccess(o, "File has been deleted (May still exist in database)");
						resultListModel.removeElement(o);
					}
					else {
						Dialogs.showError(o, "File not deleted.");
					}
				}
			}
		};
		deleteFileAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
		
		editExtensionAction = new AbstractAction("Edit Extension", DBImages.DOC_EDIT_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				openExtensionDialog(false);
			}
		};
		editExtensionAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E);
		
		addExtensionAction = new AbstractAction("Add Extension", DBImages.DOC_ADD_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				openExtensionDialog(true);
			}
		};
		addExtensionAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
		
		deleteExtensionAction = new AbstractAction("Delete Extension", DBImages.REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				deleteExtension();
			}
		};
		deleteExtensionAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
		
		applyLookAndFeelAction = new AbstractAction("Apply Look & Feel", DBImages.APPLY_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				if (!checkAccess(resultList.getSelectedValue())) return;
				Utils.applyLookAndFeel(resultList.getSelectedValue(), AdminWindow.this);
			}
		};
		applyLookAndFeelAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_L);
		
		unAssignAction = new AbstractAction("Unassign", DBImages.USER_REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				unAssignDocument();
			}
		};
		unAssignAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_U);
		
		approveAction = new AbstractAction("Approve", DBImages.APPLY_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent a) {
				String APPROVE_COPY_ERROR = "Copy error while approving document";
				showWaitCursor(true);
				try {
					approveDocument();
				}
				catch (Exception e) {
					Dialogs.showError(e, APPROVE_COPY_ERROR);
				}
				showWaitCursor(false);
			}
		};
		approveAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
		
		assignAction = new AbstractAction("Assign", DBImages.DOC_SEND_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				assignDocuments(resultList.getSelectedValues());
			}
		};
		assignAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
		
		documentPropertiesAction = new AbstractAction("Properties", DBImages.DOC_EDIT_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				new DocumentPropertiesDialog(AdminWindow.this, 
					userAccount, resultList.getSelectedValue()).setVisible(true);
			}
		};
		assignAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);	
		
		editColorAction = new AbstractAction("Edit Color", DBImages.COLOR_ICON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				//
			}
		};
		editColorAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E);
		
		editCategoryAction = new AbstractAction("Edit Category", DBImages.EDIT_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				Dialogs.categoryDialog((String)resultList.getSelectedValue());
			}
		};
		editCategoryAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_E);
		
		addCategoryAction = new AbstractAction("Add Category", DBImages.ADD_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				if (DBController.addCategory(Dialogs.showInputDialog("Category", "New category name:")))
					listCategories();
			}
		};
		addCategoryAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_A);
		
		deleteCategoryAction = new AbstractAction("Delete Category", DBImages.REMOVE_BUTTON.getIcon()) {
			public void actionPerformed(ActionEvent e) {
				deleteCategory();
			}
		};
		deleteCategoryAction.putValue(Action.MNEMONIC_KEY, KeyEvent.VK_D);
		
		/*
		 * Set up sort-of global hotkeys that are neither handled through
		 * mnemonics nor accelerators already.
		 */
		InputMap inputMap = new ComponentInputMap((JComponent)getContentPane());
		inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DELETE_INPUT_KEY);
		
		ActionMap actionMap = new ActionMap();
		actionMap.put(DELETE_INPUT_KEY, deleteAction);
		
		((JComponent)getContentPane()).setInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW, inputMap);
		((JComponent)getContentPane()).setActionMap(actionMap);
		/**/
	}
	
	/**
	 * Backs-up, then clears-out the document listing 
	 * and repopulates the database with the document 
	 * list returned by Utils.searchForDocs()
	 */
	private void repopulateDocuments() throws SQLException {
		folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		folderChooser.setCurrentDirectory(new File(Utils.getDocRoot()));
		Object input = folderChooser.showOpenDialog(this);
		final File folder = ((Integer)input == JFileChooser.CANCEL_OPTION ? null : folderChooser.getSelectedFile());
		resultListModel.clear();
		final Set<WeightedDocument> foundDocs;// = new TreeSet<WeightedDocument>();
		threadWorker.scanForDocuments(userAccount, folder, this, resultListModel);
	}
	
	
	private void addListeners() {
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				closeWindow();
			}
		});
		
		navigatorTree.addTreeSelectionListener(new TreeSelectionListener() {
			public void valueChanged(TreeSelectionEvent e) {
				resultList.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
				resultList.setModel(resultListModel);
				resultScroll.setViewportView(resultList);
				DefaultMutableTreeNode node = (DefaultMutableTreeNode)navigatorTree.getLastSelectedPathComponent();
				PathComponents p = (PathComponents)node.getUserObject();
				switch (p) {
					case ADMIN:
						break;
					case DOCUMENTS:
						break;
					case DUE_DOCUMENTS:
						listDueDocs(); break;
					case ALL_DOCUMENTS:
						listAllDocs(); break;
					case ASSIGNED_DOCUMENTS:
						listAssignedDocs(); break;
					case AWAITING_DOCUMENTS:
						listAwaitingDocs(); break;
					case USERS:
						listUsers(); break;
					case DEPARTMENTS:
						listDepartments(); break;
					case EXTENSIONS:
						listExtensions(); break;
					case CATEGORIES:
						listCategories(); break;
					case FILE_SERVERS:
						listFileServers(); break;
					case ICONS:
						listImages(); break;
					case LOOK_AND_FEEL:
						listLookAndFeel(); break;
					case COLORS:
						listAllColors(); break;
					case DATABASE_FUNCTIONS:
						listDatabaseActions(); break;
					default:
						listNothing(); break;
				}
			}
		});
		
		resultList.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if(e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
					openDialogWindow(resultList.getSelectedValue());
				}
			}
			
			public void mousePressed(MouseEvent e) {
				if(e.isPopupTrigger()) {
					showListPopupMenu(e.getPoint());
				}
			}
			
			public void mouseReleased(MouseEvent e) {
				if(e.isPopupTrigger()) {
					showListPopupMenu(e.getPoint());
				}
			}
		});
		
		new FileDrop(resultList, /*dragBorder,*/ new FileDrop.Listener() {
			public void filesDropped(File[] files) {
				File lastFile = null;
				int goodFileCount = 0;
				Document d = null; //Temp document
				for (File i : files) {
					try {
						if (DBController.isSupportedFile(i)) {
							if (Utils.copyFile(i.getCanonicalPath(), Utils.getUserRoot(userAccount) + i.getName())) {
								goodFileCount++;
								d = Utils.createDocument(i, userAccount);
								DBController.addDocument(d, userAccount);
								lastFile = i;
							}
						}
					}
					catch(IOException e) {}
				}
				if (goodFileCount > 0) {
					//listOwedDocs(userName);
					listAllDocs();
					statusBar.setLabelText(goodFileCount + " file" + (goodFileCount>1 ? "s" : "") + " added to listing.");
					//resultList.setSelectedValue(lastFile.getName(), true);
					//populateDocs(true);
					//populateDocs(allDocumentsListModel, resultsList);
					resultList.setSelectedValue(d, true);
				}
				else 
					statusBar.setLabelText("Document \"" + lastFile.getName() + "\" not supported.");
			}
		});
	}
	
	private void showListPopupMenu(Point p) {
		if (listPopupMenu.getComponentCount() > 0) {
			if (resultList.getSelectionMode() == ListSelectionModel.SINGLE_SELECTION)
				resultList.setSelectedIndex(resultList.locationToIndex(p));
			
			listPopupMenu.show(resultList, p.x, p.y);
		}
	}
	
	private void repopulateDatabase() {
		if (Dialogs.showConfirm(Lang.ADMIN_DIALOG.get("REPOPULATE_CONFIRM", "Are you sure?"))) {
			resultListModel.clear();
			try {
				showWaitCursor(true);
				repopulateDocuments();
				showWaitCursor(false);
			}
			catch (SQLException sql) {
				Dialogs.showError(sql, "Something went wrong while repopulating");
			}
		}
		else
			Dialogs.showError("Repopulate canceled");
	}
	
	private void listDatabaseActions() {
		resultListModel.clear();
		setPanelActions(repopulateDatabaseAction, null, null, null, null);
	}

	private void listFileServers() {
		resultListModel.clear();
		resultListModel.addAll(DBController.getFileServers());
		setPanelActions(null, null, null, null, null);
		ViewMode.listMode = ViewMode.FILESERVER_MODE;
	}
	
	private void closeWindow() {
		ClientWindow window = new ClientWindow();
		try {
			window.loginUser(userAccount);
			window.setVisible(true);
			dispose();
		}
		catch(SQLException e) {
			Main.printStackTrace(e, "Error reloading DBClientWindow");
		}
	}
	
	//private void listAllDocs() {
	//	listAllDocs(null);
	//}
	
	/**
	 * What to do when nothing is listed
	 * (To be determined)
	 */
	private void listNothing() {
		ViewMode.listMode = ViewMode.NULL_MODE;
		resultListModel.clear();
		setPanelActions(null, null, null, null, null);
	}
	
	private void listCategories() {
		ViewMode.listMode = ViewMode.CATEGORY_MODE;
		showWaitCursor(true);
		setPanelActions(editCategoryAction, addCategoryAction, deleteCategoryAction, null, null);
		resultListModel.clear();
		resultListModel.addAll(DBController.getCategories());
		statusBar.setLabelText("" + resultListModel.getSize() + " categories listed");
		resultList.setSelectedIndex(0);
		resultList.requestFocusInWindow();
		showWaitCursor(false);
	}
	
	private void deleteDepartment() {
		Dialogs.showError(resultList.getSelectedValue(), "Not yet coded.");
		//
	}
	
	private void deleteCategory() {
		Object o = resultList.getSelectedValue();
		if (Dialogs.confirmDelete(o)) {
			if (!DBController.deleteCategory((String)o))
				Dialogs.showError(o, "Error deleting category.  Note: Minimum of 1 Category needed.");
			else
				resultListModel.removeElement(o);
		}
	}
	
	private boolean approveDocument() throws Exception {
		Object o = resultList.getSelectedValue();
		if (!(o instanceof Document))
			return Dialogs.showError(o, "Wrong document type.  Can't be approved.");
		
		String APPROVE_CHOOSE = "Choose a destination";
		String APPROVE_SUCCESS = "Successfully approved document";
		String APPROVE_COPY_ERROR = "Copy error while approving document";
		QuickIni settings = Main.userIni;
		Document doc = (Document)o;
		
		String dialogPath = settings.getStringProperty("History", "last_approve");
		if (dialogPath == null || dialogPath.trim().equals(""))
			dialogPath = Utils.getDocRoot();
		
		File fSrce = doc.toAwaitingFile(userAccount);
		File fDest;
		Document d = DBController.docQuery(fSrce);
		if (d != null && d.isApproved() && d.toFile().exists()) {
			fDest =  d.toFile();
		}
		else {
			File destFolder = showSaveDialog(APPROVE_CHOOSE, dialogPath);
			if (destFolder == null)
				return false;
			fDest = new File(destFolder.getPath()  + "/" + fSrce.getName());
		}
		settings.setStringProperty("History", "last_approve", fDest.getParentFile().getPath());
		
		if (Utils.copyFile(fSrce, fDest)) {
			fSrce.delete();
			DBController.updateDocumentPath((Document)o, fDest);
			DBController.updateDocumentDate(d);
			DBController.setDocumentApproved(d);
			listAwaitingDocs();
			if (d.getNewDocumentName() != null) {
				archiveDocument(o);
				d.toFile().renameTo(d.toApprovedFile(userAccount));
				DBController.renameDocument(d, d.getNewDocumentName(), true);
			}
			return Dialogs.showSuccess(o, APPROVE_SUCCESS);
		}
		throw new Exception(APPROVE_COPY_ERROR);
	}
	
	private void openDialogWindow(Object o) {
		switch (ViewMode.listMode) {
			case COLOR_MODE:
				((Colors)o).showDialog(this);
				break;
			case LOOKANDFEEL_MODE:
				Utils.applyLookAndFeel(o, this);
				break;
			case USER_MODE:
				openUserDialog(false);
				break;
			case DEPARTMENT_MODE: 
				showDepartmentDialog(o);
				break;
			case AWAITING_MODE:
				ClientWindow.openDocumentEdit(((Document)o).toAwaitingFile(userAccount), userAccount, true);
				break;
			case ASSIGNED_MODE:
				ClientWindow.openDocumentEdit(((Document)o).toAssignedFile(userAccount), userAccount, true);
				break;
			case DOCUMENT_MODE:
				ClientWindow.openDocumentReadOnly(((Document)o).toFile(), true);
				break;
			case EXTENSION_MODE: 
				openExtensionDialog(false);
				break;
			case CATEGORY_MODE:
				Dialogs.categoryDialog((String)o);
				break;
			default: break;
		}
	}
	
	private void showDepartmentDialog(Object o) {
		try {
			if (o != null) {
				DepartmentPropertiesDialog propertiesDialog = new DepartmentPropertiesDialog(o.toString(), AdminWindow.this);
				propertiesDialog.setVisible(true);
			}
			else {
				Dialogs.showError(o, "Feature not yet available (Create department)" + 
					Dialogs.showInputDialog(o, "Please enter new department name:"));
			}
		}
		catch(SQLException ex) {
			Dialogs.showError(ex, o, "Couldn't open properties dialog.");
		}
	}
	
	private void listAllDocs() {
		ViewMode.listMode = ViewMode.DOCUMENT_MODE;
		setPanelActions(assignAction, documentPropertiesAction, null, null, deleteDocumentAction);
		resultListModel.clear();
		resultList.setModel(allDocumentsListModel);
		try {
			threadWorker.listAllDocumentsThread();
		}
		catch (Exception e) {
			Dialogs.showError(e);
		}
		//populateDocs();
		//populateDocs(false);
	}

	private void listAssignedDocs() {
		ViewMode.listMode = ViewMode.ASSIGNED_MODE;
		showWaitCursor(true);
		setPanelActions(unAssignAction, null, null, null, null);

		resultTableModel.setRowCount(0);
		resultTableModel.setColumnCount(0);
		
		resultTableModel.addColumn("Document Name");
		resultTableModel.addColumn("Assignee");
		resultTableModel.addColumn("Review Date");
		
		java.util.List<Document> assignedList = DBController.getAssignedDocuments(userAccount.getDepartmentName());
		for (Document d :  assignedList)
			resultTableModel.addRow(
				new Object[] {
					d, d.getAssignee(true), d.getEffectiveDate()
				});
		resultTable.setDefaultRenderer(resultTable.getColumnClass(0),tableRenderer);
		resultScroll.setViewportView(resultTable);
		showWaitCursor(false);
	}
	
	private void unAssignDocument() {
		int row = resultTable.getSelectedRow();
		if (row < 0) return;
		Document d = (Document)resultTableModel.getValueAt(row, 0);
		User u = (User)resultTableModel.getValueAt(row, 1);
		File f = new File(Utils.getUserRoot(u) + d.getFullName());
		Main.printDebug(d.getDocumentName());
		resultTableModel.removeRow(row);
		if (DBController.assignDocument(d, null)) {
			Dialogs.showSuccess(d, "Successfully unassigned:");
			if (f.exists())
				if (f.delete())
					Dialogs.showSuccess("Successfully deleted:\n" + f.getPath());
				else
					Dialogs.showError("Error deleting: " + f.getPath()); 
			else
				Dialogs.showError("Error, could not find: " + f.getPath()); 
		}
		else
			Dialogs.showError("Error unassigning document");
	}
	
	private void listLookAndFeel() {
		ViewMode.listMode = ViewMode.LOOKANDFEEL_MODE;
		showWaitCursor(true);
		String thisLaf = UIManager.getLookAndFeel().getName().trim().replace(" ", "_");
		resultListModel.clear();
		resultListModel.addAll(UIManager.getInstalledLookAndFeels());
		setPanelActions(applyLookAndFeelAction, null, null, null, null);
		for (int i = 0; i < resultListModel.getSize(); i++) {
			String listLaf = ((LookAndFeelInfo)resultListModel.get(i)).getName();
			if (thisLaf.equalsIgnoreCase(listLaf)) {
				resultList.setSelectedIndex(i);
				break;
			}
		}
		showWaitCursor(false);
	}
	
	/**
	 * Simple save dialog
	 */
	private File showSaveDialog(String title, String path) {
		File pathFile = new File(path);
		if (pathFile.exists())
			folderChooser.setCurrentDirectory(pathFile);
		folderChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
		folderChooser.setDialogTitle(title);
		if(folderChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION)
			return folderChooser.getSelectedFile();
		return null;
	}
	
	private void listImages() {
		ViewMode.listMode = ViewMode.ICON_MODE;
		resultListModel.clear();
		for (DBImages i : DBImages.values()) {
			resultListModel.addElement(i);
		}
		ViewMode.listMode = ViewMode.NULL_MODE;
		setPanelActions(null, null, null, null, null);
	}
	
	private void listAllColors() {
		ViewMode.listMode = ViewMode.COLOR_MODE;
		showWaitCursor(true);
		setPanelActions(editColorAction, null, null, null, null);
		resultListModel.clear();
		resultListModel.addElement(Colors.dueColor);
		resultListModel.addElement(Colors.alertColor);
		resultListModel.addElement(Colors.overDueColor);
		//resultListModel.addElement(Colors.defaultColor);
		resultListModel.addElement(Colors.departmentColor);
		showWaitCursor(false);
	}
	
	private void listExtensions() {
		ViewMode.listMode = ViewMode.EXTENSION_MODE;
		showWaitCursor(true);
		setPanelActions(editExtensionAction, addExtensionAction, deleteExtensionAction, null, null); 
		resultListModel.clear();
		resultListModel.addAll(DBController.getExtensions());
		resultList.setSelectedIndex(0);
		statusBar.setLabelText("" + resultListModel.getSize() + " extensions listed");
		showWaitCursor(false);
	}
	
	private void listAwaitingDocs() {
		ViewMode.listMode = ViewMode.AWAITING_MODE;
		showWaitCursor(true);
		setPanelActions(approveAction, documentPropertiesAction, deleteFileAction, null, null);
		resultList.setToolTipText("Documents awaiting updating");
		resultListModel.clear();
		File f = new File(Utils.getDoneRoot(userAccount));
		if (!f.isDirectory()) {
			Main.printDebug("Directory does not exists.  Attempting to create...");
			if (f.mkdir()) Main.printDebug("Directory created successfully.");
			else {
				Dialogs.showError("Could not create folder " + Utils.getDoneRoot(userAccount) + " results cannot be listed.");
				return;
			}
		}
		
		java.util.List<Document> docs = new ArrayList<Document>();
		for (File i : f.listFiles()) {
			if (DBController.isSupportedFile(i) && !i.getName().startsWith("~")) { 
				Document d = DBController.docQuery(i);
				if (d == null)
					docs.add(Utils.createDocument(i, userAccount));
				else
					docs.add(d);
			}
		}
		
		Collections.sort(docs);
		
		resultListModel.addAll(docs);

		resultList.setSelectedIndex(0);
		resultList.requestFocusInWindow();
		
		statusBar.setLabelText("" + resultListModel.getSize() + " documents listed");
		showWaitCursor(false);
	}
	
	private void listDueDocs() {
		ViewMode.listMode = ViewMode.DOCUMENT_MODE;
		showWaitCursor(true);
		resultList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		setPanelActions(assignAction, documentPropertiesAction, null, null, deleteDocumentAction);
		Set<WeightedDocument> weightedResults = new TreeSet<WeightedDocument>();
		for (Document d : DBController.searchDueDocuments(userAccount, DUE_MONTHS_AHEAD))
			weightedResults.add(new WeightedDocument(d, Utils.daysDue(d)));
			
		resultListModel.clear();
		
		int weight = -1;
		for(WeightedDocument wsr : weightedResults) {
			if (weight == -1 && wsr.getWeight() > 0) {
				resultListModel.addElement("~ Overdue ~");
				weight = 0;
			}
			else if (weight <= 0 && wsr.getWeight() <= 0) {
				resultListModel.addElement("~ Due within the next " + (int)(DUE_MONTHS_AHEAD*30.4375)  + " days ~");
				weight = 1;
			}
			if (wsr.isApproved()) resultListModel.addElement(wsr);
		}
		statusBar.setLabelText("" + (resultListModel.getRelevantSize()) + " due documents listed");
		if (resultListModel.getSize() < 1)
			resultListModel.addElement("~ No Due Documents ~");
		resultList.setSelectedIndex(0);
		showWaitCursor(false);
	}
	
	private void setPanelActions(Action firstAction, Action secondAction, Action thirdAction, Action fourthAction, Action fifthAction) {
		Action[] allActions = {firstAction, secondAction, thirdAction, fourthAction, fifthAction};
		
		listPopupMenu.removeAll();
		buttonPanel.removeAll();
		int buttonCount = 0;
		for (int i = 0; i < panelButtons.length; i++) {
			if (allActions[i] != null) {
				buttonCount++;
				panelButtons[i].setAction(allActions[i]);
				panelButtons[i].setText("" + panelButtons[i].getText()); //Refresher?
				menuItems[i].setAction(allActions[i]);
				listPopupMenu.add(menuItems[i]);
				buttonPanel.add(panelButtons[i]);
			}
		}
		buttonGrid.setColumns(buttonCount);
		
		listPopupMenu.pack();
		validate();
	}
	
	private void setPanelToolTips(String firstTip, String secondTip, String thirdTip, String fourthTip, String fifthTip) {
		String[] allTips = {firstTip, secondTip, thirdTip, fourthTip, fifthTip};
		for (int i = 0; i < panelButtons.length; i++) {
			panelButtons[i].setToolTipText(allTips[i]);
		}
	}
	
	private void listUsers() {
		listUsers(null);
	}
	
	private java.util.List<User> listUsers(String departmentName) {
		ViewMode.listMode = ViewMode.USER_MODE;
		showWaitCursor(true);
		Main.setCursor(this, Cursor.WAIT_CURSOR);
		
		java.util.List<User> allUsers = null;
		java.util.List<String> allDepartments = null;
		
		try {
			allUsers = DBController.getUsers(departmentName);
			allDepartments = DBController.getAllDepartments();
		}
		catch(SQLException ex) {
			Main.printStackTrace(ex, "SQL error while listing users.");
			Main.setCursor(this, Cursor.DEFAULT_CURSOR);
			showWaitCursor(false);
			return null;
		}
		
		if (departmentName != null) {
			boolean badDept = true;
			for (String d : allDepartments)
				if (d.equalsIgnoreCase(departmentName)) badDept = false;
			
			if (badDept) {
				Dialogs.showError("Error listing users for dept: " + departmentName);
				Main.setCursor(this, Cursor.DEFAULT_CURSOR);
				return null;
			}
			Main.setCursor(this, Cursor.DEFAULT_CURSOR);
			showWaitCursor(false);
			return allUsers;
		}
		else {
			setPanelActions(editUserAction, addUserAction, deleteUserAction, null, null);
			setPanelToolTips(Lang.TOOL_TIP.get("EDIT_USER"), 
			Lang.TOOL_TIP.get("NEW_USER"), 
			Lang.TOOL_TIP.get("DELETE_USER"), null, null);
			resultListModel.clear();
			
			Set<WeightedUser> weightedResults = new TreeSet<WeightedUser>();
			for (User u : allUsers)
				weightedResults.add(new WeightedUser(u, allDepartments.indexOf(u.getDepartmentName())));
			
			int previousWeight = -1;
			int maxWeight = 0;
			for(WeightedUser wsr : weightedResults) {
				if (previousWeight == -1 || wsr.getWeight() < previousWeight) {
					resultListModel.addElement("~ " + ((User)wsr).getDepartmentName() + " ~");
					previousWeight = wsr.getWeight();
				}
				resultListModel.addElement(wsr);
				maxWeight = (previousWeight>maxWeight)? previousWeight:maxWeight;
			}
			statusBar.setLabelText("" + (resultListModel.getSize() - maxWeight) + " users listed");
			resultList.setSelectedIndex(0);
		}
		showWaitCursor(false);
		return null;
	}
	
	private void openUserDialog(boolean newUser) {
		Object s = resultList.getSelectedValue();
		UserDialog d;
		if (newUser) {
			d = new UserDialog(this, userAccount);
		}
		else if (!(s.toString().startsWith("~")) && s != null) {
			User u = (User)s;
			d = new UserDialog(this, u, userAccount);
		}
		else
			return;
		d.setVisible(true);
		if (d.isSuccessful()) {
			listUsers();
		}
	}
	
	private boolean openExtensionDialog(boolean newExtension) {
		Object s = resultList.getSelectedValue();
		String xmlError = Lang.DIALOG.get("CONFIG_XML", "Sorry, the \"xml\" format is dynamic and not configurable");
		ExtensionDialog d;
		if (s.toString().equalsIgnoreCase("xml")) {
			return Dialogs.showError(xmlError);
		}
		else if (newExtension)
			d = new ExtensionDialog(this, userAccount);
		else if (!(s.toString().startsWith("~")) && s != null)
			d = new ExtensionDialog(this, (String)s , userAccount);
		else
			return false;
		d.setVisible(true);
		if (d.isSuccessful()) {
			listExtensions();
		}
		return true;
	}
	
	private void deleteExtension() {
		Object o = resultList.getSelectedValue();
		if (o == null)
			return;
		String s = (String)o;
		if (Dialogs.confirmDelete(s)) {
			int i = resultList.getSelectedIndex();
			if (DBController.deleteExtension(s)) {
				listExtensions();
				resultList.setSelectedIndex(i);
			}
			else {
				Dialogs.showError(o, "Deletion failed");
			}	
		}
	}
	
	private void deleteUser() {
		Object s = resultList.getSelectedValue();
		String t = s.toString();
		if (t.startsWith("~") || t.equals("") || (s == null))
			return;
		User u = (User)s;
		if (Dialogs.confirmDelete(u)) {
				int i = resultList.getSelectedIndex();
				if (DBController.deleteUser(u)) {
					listUsers();
					resultList.setSelectedIndex(i);
				}
				else {
					Dialogs.showError("Deletion failed");
				}
					
		}
	}
	
	/** Assign documents to unknown user */
	private void assignDocuments(Object[] docs) {
		showWaitCursor(true);
		if (!checkAccess(docs))
			return;
		int count = 0;
		int success = 0;
		User u = (User)Dialogs.showListDialog(this, listUsers(userAccount.getDepartmentName()));
		for (Object o : docs) {
			if (o instanceof Document && docs != null) {
				count++;
				if (assignDocument((Document)o, u)) {
					success++;
					resultListModel.removeElement(o);
				}
			}
		}
		
		if (count > 0) {
			Dialogs.showSuccess("Successfully assigned " + success + "/" + count + " documents to " + u.getUserName());
			resultList.setSelectedIndex(0);
		}
		showWaitCursor(false);
	}
	
	/** Assign document to known user */
	private boolean assignDocument(Document d, Object o) {
		if (!(o instanceof User) || o == null || !checkAccess(d)) return false;
		User u = (User)o;
		File fDest = new File(Utils.getUserRoot(u) + d.getFullName());		
		try {
			return (Utils.copyFile(d.toFile(), fDest)) && (DBController.assignDocument(d, u));
		}
		catch (IOException e) {
			Dialogs.showError(e, "Error: " + d.getDocumentName() + " could not be found.  Program will continue.");
		}
		return false;
	}
	
	private boolean checkAccess(Object o) {
		String errorMsg = "You do not have access to perform this function.";
		if (o instanceof Document || o instanceof Document[]) {
			Document d = (Document)o;
			if (!d.getDepartmentName().equalsIgnoreCase(userAccount.getDepartmentName())) {
				return Dialogs.showError(errorMsg + "You are limited to your own department: " + userAccount.getDepartmentName());
			}
		}
		
		/*else if (o instanceof LookAndFeelInfo) {
			if (!userAccount.isAdmin()) 
				return Dialogs.showError(errorMsg);
		}*/
		return true;
	}
	
	private boolean archiveDocument(Object o) {
		try {
			if (o instanceof Document) {
				Document d = (Document)o;
				return Utils.copyFile(d.toFile(), d.toArchivedFile());
			}
		}
		catch (IOException e) {}
		return false;
	}
	
	private void deleteDocument(Object o) {
		if (!(o instanceof Document))
			return;
		Document d = (Document)o;

		if (Dialogs.confirmDelete(d)) {
			/* Seems to be working -- Needs testing */
			boolean isDeleted = false;
			boolean canDeleteFromDB = false;
			String failedProc = "copy/archive process (file may not exist)";
			String msg =  "Deletion ";
			try {
				if (archiveDocument(d))
					canDeleteFromDB = true;
				else
					canDeleteFromDB = Dialogs.showAlertConfirm(d, msg + "failed (" + failedProc + ") Delete anyways?");
				if (canDeleteFromDB) {
					failedProc = "deletion from database";
					if (DBController.deleteDocument(d)) {
						int listIndex = resultList.getSelectedIndex();
						//resultListModel.removeElement(d);
						//allDocuments.remove(d);
						allDocumentsListModel.removeElement(d);
						resultList.setSelectedIndex(listIndex);
						failedProc = "deletion of actual file (if copy process failed, this is normal)";
						if (d.toFile().delete())
							isDeleted = true;
					}
				}
			} 
			catch (Exception e) {
				Dialogs.showError(e, d, msg + "failed (" + failedProc + ")");
			}
			if (isDeleted)
				Dialogs.showSuccess(d, msg + "succeeded");
			else
				Dialogs.showError(d, msg + "failed (" + failedProc + ")");
		}
	}
	
	private void listDepartments() {
		ViewMode.listMode = ViewMode.DEPARTMENT_MODE;
		showWaitCursor(true);
		setPanelActions(editDepartmentAction, addDepartmentAction, deleteDepartmentAction, null, null);
		resultListModel.clear();
		java.util.List<String> resultElements = null;
		try {
			resultListModel.addAll(DBController.getAllDepartments());
		}
		catch(SQLException ex) {
			Main.printStackTrace(ex, "SQL error while listing departments.");
			return;
		}
		
		statusBar.setLabelText("" + resultListModel.getSize() + " groups listed");
		resultList.setSelectedIndex(0);
		showWaitCursor(false);
	}
	
	private void showWaitCursor(boolean show) {
		if (show) 
			Main.setCursor(AdminWindow.this, Cursor.WAIT_CURSOR);
		else 
			Main.setCursor(AdminWindow.this, Cursor.DEFAULT_CURSOR);
	}
}
